#include "collectibleentity.h"

#include "application.h"
#include "serviceentity.h"
#include "graphics/graphicsmanager.h"

#include "graphics/texturemanager.h"
#include "graphics.opengl/texture.h"
#include "graphics/texture.h"

#include "servicecamera.h"
#include "object.h"
#include "worldgridmanager.h"

#include "graphicsmodel.h"

namespace infinity {

/*static*/ const dw::float32 CollectibleEntity::InfiniteTime = std::numeric_limits< dw::float32 >::infinity();

/*virtual*/ void CollectibleEntity::renderDebug()
{
	super::renderDebug();

	/*
	if (m_physicObject != NULL)
	{
		dw::graphics::Renderer& renderer(dw::graphics::GraphicsManager::getInstance().getRenderer());
		const Matrix4f& objectMtx = m_physicObject->getTransform();

		renderer.pushState();
	
		renderer.setMatrixMode(dw::graphics::Renderer::MODELVIEW);
		renderer.pushMatrix();

		renderer.multMatrix(objectMtx);

		renderer.setRenderState(dw::graphics::Renderer::RS_DEPTH_TEST, true);
		renderer.setRenderState(dw::graphics::Renderer::RS_LIGHTING, false);
		renderer.setRenderState(dw::graphics::Renderer::RS_ALPHA_TEST, false);

		const WorldGridManager& worldManager = WorldGridManager::getInstance();
	
		if(m_object.type == Object::BLOC || m_object.type == Object::ENTITY_BLOC)
		{
			const MaterialLibrary& materialLib = worldManager.getPlanet()->getMaterialLibrary();
			const Material& material = materialLib.getMaterialFromId(m_object.id);
			dw::graphics::ITexture* tex = dw::graphics::TextureManager::getInstance().getTexture("terrain.png");
			renderer.setTexture(tex);

			dw::maths::Vector2f upleft = material.getOffsetSide();
			float sizecell = 1/16.0f;

			glBegin(GL_QUADS);
			// Front Face
			glNormal3f( 0.0f, 0.0f, 1.0f);
			glTexCoord2f(upleft.x, upleft.y + sizecell ); glVertex3f(-0.2f, -0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( 0.2f, -0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f( 0.2f,  0.2f,  0.2f);	// Top Right Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f(-0.2f,  0.2f,  0.2f);	// Top Left Of The Texture and Quad
			// Back Face
			glNormal3f( 0.0f, 0.0f,-1.0f);
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f(-0.2f, -0.2f, -0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f(-0.2f,  0.2f, -0.2f);	// Top Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f( 0.2f,  0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( 0.2f, -0.2f, -0.2f);	// Bottom Left Of The Texture and Quad

			upleft = material.getOffsetTop();

			// Top Face
			glNormal3f( 0.0f, 1.0f, 0.0f);
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f(-0.2f,  0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f(-0.2f,  0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f( 0.2f,  0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( 0.2f,  0.2f, -0.2f);	// Top Right Of The Texture and Quad

			upleft = material.getOffsetBottom();

			// Bottom Face
			glNormal3f( 0.0f,-1.0f, 0.0f);
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f(-0.2f, -0.2f, -0.2f);	// Top Right Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f( 0.2f, -0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f( 0.2f, -0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y); glVertex3f(-0.2f, -0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			
			 upleft = material.getOffsetSide2();
			// Right face
			glNormal3f( 1.0f, 0.0f, 0.0f);
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( 0.2f, -0.2f, -0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f( 0.2f,  0.2f, -0.2f);	// Top Right Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f( 0.2f,  0.2f,  0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f( 0.2f, -0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			// Left Face
			glNormal3f(-1.0f, 0.0f, 0.0f);
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f(-0.2f, -0.2f, -0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f(-0.2f, -0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f(-0.2f,  0.2f,  0.2f);	// Top Right Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y ); glVertex3f(-0.2f,  0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glEnd();
		}
		else if(m_object.type == Object::ENTITY)
		{

			const ItemMaterialLibrary& materialLib = worldManager.getPlanet()->getItemMaterialLibrary();
			const ItemMaterial& material = materialLib.getMaterialFromId(m_object.id);

			dw::graphics::ITexture* tex = dw::graphics::TextureManager::getInstance().getTexture("items.png");
			renderer.setTexture(tex);

			dw::maths::Vector2f upleft = material.getOffset();
			float sizecell = 1/16.0f;
		
			renderer.setRenderState(dw::graphics::Renderer::RS_CULLING, false);
			renderer.setRenderState(dw::graphics::Renderer::RS_CULL_MODE, dw::graphics::Renderer::CullMode::FRONT_AND_BACK);

			
			glBegin(GL_QUADS);
			// Front Face
			glNormal3f( 0.0f, 1.0f, 0.0f);
			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f(0.2f, -0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y); glVertex3f( 0.2f, 0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f( -0.2f,  0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( -0.2f, -0.2f, -0.2f);	// Bottom Left Of The Texture and Quad

			glTexCoord2f(upleft.x , upleft.y + sizecell); glVertex3f(-0.2f, -0.2f,  0.2f);	// Bottom Left Of The Texture and Quad
			glTexCoord2f(upleft.x , upleft.y); glVertex3f( -0.2f, 0.2f,  0.2f);	// Bottom Right Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y ); glVertex3f( 0.2f,  0.2f, -0.2f);	// Top Left Of The Texture and Quad
			glTexCoord2f(upleft.x + sizecell, upleft.y + sizecell); glVertex3f( 0.2f, -0.2f, -0.2f);	// Bottom Left Of The Texture and Quad

			glEnd();

		}


		
		
		renderer.popState();
		renderer.popMatrix();
	}
	// */
}

/*virtual*/ CollectibleEntity::~CollectibleEntity()
{
}

/*virtual*/ Entity::State CollectibleEntity::onInitializeSimulation()
{
	State superState = super::onInitializeSimulation();

	if (superState == State_Initialized)
	{
		dwAssert(m_physicObject == NULL, "Invalid internal state");
		m_physicObject = Application::getInstance().getService< ServicePhysics >().createObject();

		if (m_physicObject != NULL)
		{
			m_physicObject->setPosition(m_initialPosition);
			m_physicObject->applyImpulse(m_initialVelocity);
		}

		return (m_physicObject != NULL) ? State_Initialized : State_InitializationFailed;
	}

	return superState;
}

/*virtual*/ void CollectibleEntity::onUpdateSimulation(dw::float32 deltaT)
{
	super::onUpdateSimulation(deltaT);

	if (m_timeToLive != InfiniteTime)
	{
		m_timeToLive -= deltaT;

		if (m_timeToLive < 0.0f)
		{
			Application::getInstance().getService< ServiceEntity >().condemnEntity(this);
		}
	}
}

/*virtual*/ Entity::State CollectibleEntity::onTerminateSimulation()
{
	if (m_physicObject != NULL)
	{
		Application::getInstance().getService< ServicePhysics >().releaseObject(m_physicObject);
		m_physicObject = NULL;
	}

	return super::onTerminateSimulation();
}

/*virtual*/ Entity::State CollectibleEntity::onInitializeMedia()
{
	State superState = super::onInitializeMedia();

	if (superState == State_Initialized && m_graphicsModel == NULL)
	{
		std::string meshName;

		if (m_object.type == Object::BLOC || m_object.type == Object::ENTITY_BLOC)
		{
			const MaterialLibrary& materialLib = WorldGridManager::getInstance().getPlanet()->getMaterialLibrary();
			const Material& material = materialLib.getMaterialFromId(m_object.id);
			meshName = ServiceGraphics::CollectiblesBlocksPath + material.getName();
		}
		else
		{
			const ItemMaterialLibrary& materialLib = WorldGridManager::getInstance().getPlanet()->getItemMaterialLibrary();
			const ItemMaterial& material = materialLib.getMaterialFromId(m_object.id);
			meshName = ServiceGraphics::CollectiblesItemsPath + material.getName();
		}

		m_graphicsModel = Application::getInstance().getService< ServiceGraphics >().createModel(ServiceGraphics::GROUP_ENTITIES, meshName);

		if (m_graphicsModel != NULL && m_physicObject != NULL)
		{
			m_graphicsModel->setTransform(m_physicObject->getTransform());
		}

		return (m_graphicsModel != NULL) ? State_Initialized : State_InitializationFailed;
	}

	return superState;
}

/*virtual*/ void CollectibleEntity::onUpdateMedia(dw::float32 deltaT)
{
	super::onUpdateMedia(deltaT);

	if (m_graphicsModel != NULL && m_physicObject != NULL)
	{
		m_graphicsModel->setTransform(m_physicObject->getTransform());
	}
}

/*virtual*/ Entity::State CollectibleEntity::onTerminateMedia()
{
	State selfState = m_graphicsModel == NULL ? State_Terminated : State_Terminating;

	if (m_graphicsModel != NULL)
	{
		Application::getInstance().getService< ServiceGraphics >().releaseModel(m_graphicsModel);
		m_graphicsModel = NULL;

		selfState = State_Terminated;
	}

	if (selfState == State_Terminated)
	{
		return super::onTerminateMedia();
	}

	return selfState;
}

void CollectibleEntity::setObject(Object::SlotType type, int id)
{
	m_object.type = type;
	m_object.id = id;
}

} // namespace infinity
